;;;; -*- Mode: Lisp; -*-

;;; TriMesh geometry object
(in-package :dreaming-tree)

;;; Notes for trimesh pick-record params:
#| 
;; Barycentric coordinates of the point of intersection.  If b0, b1,
;; and b2 are the values, then all are in [0,1] and b0+b1+b2=1.
(bary0 :accessor bary0 :initarg :bary0 :initform nil)
(bary1 :accessor bary1 :initarg :bary1 :initform nil)
(bary2 :accessor bary2 :initarg :bary2 :initform nil)
(triangle :accessor triangle :initarg :triangle :initform nil) ; index of the triangle that is intersected by the ray
|#

(defmacro post-incf (reference &optional (delta 1))
  `(prog1
       ,reference
     (incf ,reference ,delta)))

(defun %get-vertex (v idx)
  (vector (aref v idx 0)
	  (aref v idx 1)
	  (aref v idx 2)))

(defun %set-vertex (v idx new)
  (setf (aref v idx 0) (svref new 0)
	(aref v idx 1) (svref new 1)
	(aref v idx 2) (svref new 2)))

(defun set-uv (uv idx new)
  (setf (aref uv idx 0) (svref new 0)
	(aref uv idx 1) (svref new 1))
  uv)

(defun get-triangle-quantity (indices)
  (/ (element-count indices) 3))

(defun get-model-triangle (vertices indices i)
  (let ((idx (* i 3)))
    (triangle3 (%get-vertex vertices (aref indices idx))
	       (%get-vertex vertices (aref indices (1+ idx)))
	       (%get-vertex vertices (aref indices (+ idx 2))))))

(defun get-world-triangle (vertices indices i transform)
  (let ((idx (* i 3)))
    (triangle3 (apply-forward transform (%get-vertex vertices (aref indices idx)))
	       (apply-forward transform (%get-vertex vertices (aref indices (1+ idx))))
	       (apply-forward transform (%get-vertex vertices (aref indices (+ idx 2)))))))

(defun compute-model-normals (vertices indices)
  ;; Calculate normals from vertices by weighted averages of facet planes
  ;; that contain the vertices.  TO DO.  Replace by algorithm that computes
  ;; axis of minimum cone containing the normals.
  (let ((normals (make-array (list (array-dimension vertices 0) 3) :initial-element 0.0)))
    (iter (for i below (element-count indices) by 3)
	  (let* ((iv0 (aref indices i))
		 (iv1 (aref indices (1+ i)))
		 (iv2 (aref indices (+ i 2)))
		 (rkv0 (%get-vertex vertices iv0))
		 (rkv1 (%get-vertex vertices iv1))
		 (rkv2 (%get-vertex vertices iv2))
		 (kedge1 (m- rkv1 rkv0))
		 (kedge2 (m- rkv2 rkv0))
		 (knormal (normalize (cross kedge1 kedge2))))
	    (%set-vertex normals iv0 (m+ (%get-vertex normals iv0) knormal))
	    (%set-vertex normals iv1 (m+ (%get-vertex normals iv1) knormal))
	    (%set-vertex normals iv2 (m+ (%get-vertex normals iv2) knormal))))
    (iter (for i below (array-dimension vertices 0))
	  (%set-vertex normals i (normalize (%get-vertex normals i)))
	  (finally (return normals)))))
                       
(defmethod get-triangle-indices (m idx))
(defmethod get-triangle-indices ((mesh trimesh) i)
  (with-slots ((indices i)) mesh
    (let ((base (* i 3)))
      (vector (aref indices base)
              (aref indices (1+ base))
              (aref indices (+ base 2))))))

(defmethod get-triangle-vertices ((mesh trimesh) i)
  (let ((in (get-triangle-indices mesh i)))
    (with-slots (vertices) mesh
      (values (aref vertices (svref in 0))
              (aref vertices (svref in 1))
              (aref vertices (svref in 2))))))

(provide :trimesh)

(defclass mesh-constructor ()
  ((vertices :accessor vertices :initarg :vertices :initform nil)
   (indices :accessor indices :initarg :indices :initform nil)
   (normals :accessor normals :initarg :normals :initform nil)
   (colors :accessor colors :initarg :colors :initform nil)
   (uvs :accessor uvs :initarg :uvs :initform nil)))

(defmethod create-data ((mc mesh-constructor) vquant tquant initcolor)
  (with-slots (vertices colors indices normals uvs) mc
    (let ((nc (array-dimension initcolor 0)))
      (setf vertices (make-array (list vquant 3) :initial-element 0.0)
	    indices (make-array (* 3 tquant) :initial-element 0)
	    colors (make-array (list vquant nc) :initial-element 0.0)
	    normals (make-array (list tquant 3) :initial-element 0.0)
	    uvs (make-array (list vquant 2) :initial-element 0.0))
      (dotimes (iv vquant)
	(dotimes (ic nc)
	  (setf (aref colors iv ic) (aref initcolor ic)))))))

(defmethod create-platonic-normals ((mc mesh-constructor))
  (setf (normals mc) (copy-seq (vertices mc))))

(defmethod create-platonic-uvs ((mc mesh-constructor))
  (loop for vn across (vertices mc)
     for uvn across (uvs mc)
     doing (progn
	     (if (< (abs (z vn)) 1.0)
		 (setf (x uvn) (* 0.5 (+ 1.0 (* +invpi+ (atan (y vn) (x vn))))))
		 (setf (x uvn) 0.5))
	     (setf (y uvn) (* +invpi+ (acos (z vn)))))))

(defgeneric reverse-triangle-order (mesh quantity))
(defmethod reverse-triangle-order ((mc mesh-constructor) tquant)
  (with-slots (indices) mc
    (loop for i from 0 below tquant
          doing (let* ((j1 (+ (* i 3) 1))
                       (j2 (+ j1 1))
                       (save (svref indices j1)))
                  (setf (svref indices j1) (svref indices j2)
                        (svref indices j2) save)))))

;;; NOTE: Most of the code below was automatically generated by a C to Lisp converted
;;; that I wrote (and lost) many years ago.  The style is obviously not very Lisp-y nor
;;; is it too readable, but the behavior seems to be correct (goddess help us if I actually
;;; have to debug any of the below).

(defun rectangle (ixsamples iysamples fxextent fyextent &key (color #(1.0 1.0 1.0))
		  (normals-p nil) (uvs-p nil))
  (let* ((mc (make-instance 'mesh-constructor))
	 (ivquantity (* ixsamples iysamples))
	 (itquantity (* (* 2 (- ixsamples 1)) (- iysamples 1)))
	 (finv0 (/ 1.0 (- ixsamples 1.0)))
	 (finv1 (/ 1.0 (- iysamples 1.0)))
	 fv ktmp fu iv0 iv1 iv2 iv3)
    (with-slots ((m_akvertex vertices) (m_aknormal normals)
		 (m_aiindex indices) (m_akuv uvs)) mc
      (create-data mc ivquantity itquantity color)
      (do ((i1 0 (incf i1))
	   (i 0 (+ i ixsamples)))
	  ((= i1 iysamples))
	(setf fv (* i1 finv1))
	(setf ktmp (m* (* (- (* 2.0 fv) 1.0) fyextent) (unit-y-vector 3)))	
	(do ((i0 0 (incf i0)))
	    ((= i0 ixsamples))
	  (setf fu (* i0 finv0))
	  (%set-vertex m_akvertex (+ i i0)
		       (m+ ktmp (m* (* (- (* 2.0 fu) 1.0) fxextent) (unit-x-vector 3))))))
      (let ((i 0))
	(do ((i1 0 (1+ i1)))
	    ((= i1 (- iysamples 1)))
	  (do ((i0 0 (1+ i0)))
	      ((= i0 (- ixsamples 1)))
	    (setf iv0 (+ i0 (* ixsamples i1)))
	    (setf iv1 (+ iv0 1))
	    (setf iv2 (+ iv1 ixsamples))
	    (setf iv3 (+ iv0 ixsamples))
	    (setf (svref m_aiindex (post-incf i)) iv0)
	    (setf (svref m_aiindex (post-incf i)) iv1)
	    (setf (svref m_aiindex (post-incf i)) iv2)
	    (setf (svref m_aiindex (post-incf i)) iv0)
	    (setf (svref m_aiindex (post-incf i)) iv2)
	    (setf (svref m_aiindex (post-incf i)) iv3))))
      (if normals-p
	  (do ((i 0 (incf i)))
	      ((= i itquantity))  
	    (%set-vertex m_aknormal i (unit-z-vector 3))))
      (if uvs-p
	  (do ((i1 0 (incf i1))
	       (i 0 (+ i ixsamples)))
	      ((= i1 iysamples))
	    (setf fv (* i1 finv1))
	    (do ((i0 0 (incf i0)))
		((= i0 ixsamples))
	      (setf fu (* i0 finv0))
	      (set-uv m_akuv (+ i i0)
		      (vector fu fv)))))
      mc)))

(defun disk (ishellsamples iradialsamples fradius &key (color #(1.0 1.0 1.0)) (normals-p nil)
	     (uvs-p nil))
  (let* ((mc (make-instance 'mesh-constructor))
	 (irsm1 (- iradialsamples 1)) 
	 (issm1 (- ishellsamples 1))
	 (ivquantity (+ 1 (* iradialsamples issm1)))
	 (itquantity (* iradialsamples (- (* 2 issm1) 1)))
	 (finvssm1 (/ 1.0 issm1))
	 (finvrs (/ 1.0 iradialsamples))
	 fangle fcos fsin kradial ffraction kfracradial it
	 (i 0)
	 (lidx 0))
    (with-slots ((m_akvertex vertices) (m_aknormal normals)
		 (m_aiindex indices) (m_akuv uvs) (m_buvs uvs-p)) mc  
      (create-data mc ivquantity itquantity color)
      (setf (svref m_akvertex 0) (zero-vector 3))
      (when normals-p
	(setf (svref m_aknormal 0) (unit-z-vector 3)))
      (when uvs-p
	(setf (x (svref m_akuv 0)) 0.5
	      (y (svref m_akuv 0)) 0.5))
      (dotimes (ir iradialsamples)
	(setf fangle (coerce (* (* (* 2 pi) finvrs) ir) 'single-float))
	(setf fcos (cos fangle))
	(setf fsin (sin fangle))
	(setf kradial (vector fcos fsin 0.0))
	(do ((is 1 (incf is)))
	    ((= is ishellsamples))
	  (setf ffraction (* finvssm1 is))
	  (setf kfracradial (m* ffraction kradial))
	  (setf i (+ is (* issm1 ir)))
	  (setf (svref m_akvertex i) (m* fradius kfracradial))
	  (when normals-p 
	    (setf (svref m_aknormal i) (unit-z-vector 3)))
	  (when uvs-p
	    (setf (x (svref m_akuv i)) (* 0.5 (+ 1.0 (x kfracradial)))
		  (y (svref m_akuv i)) (* 0.5 (+ 1.0 (y kfracradial)))))))
      (setf it 0)
      (do ((ir0 irsm1 ir1) 
	   (ir1 0 (incf ir1)))
	  ((= ir1 iradialsamples))
	(setf (svref m_aiindex lidx) 0)
	(setf (svref m_aiindex (+ 1 lidx)) (+ 1 (* issm1 ir0)))
	(setf (svref m_aiindex (+ 2 lidx)) (+ 1 (* issm1 ir1)))
	(incf lidx 3)
	(incf it)
	(do ((is 1 (incf is)))
	    ((= is issm1))
	  (let* ((i00 (+ is (* issm1 ir0)))
		 (i01 (+ is (* issm1 ir1)))
		 (i10 (+ i00 1))
		 (i11 (+ i01 1)))
	    (setf (svref m_aiindex lidx) i00)
	    (setf (svref m_aiindex (+ 1 lidx)) i10)
	    (setf (svref m_aiindex (+ 2 lidx)) i11)
	    (setf (svref m_aiindex (+ 3 lidx)) i00)
	    (setf (svref m_aiindex (+ 4 lidx)) i11)
	    (setf (svref m_aiindex (+ 5 lidx)) i01)
	    (incf it 2) 
	    (incf lidx 6))))
      (assert (= it itquantity))
      mc)))

(defun standard-box-mesh (fxextent fyextent fzextent &key (color #(1.0 1.0 1.0))
			  (normals-p nil) (uvs-p nil) (inside-p nil))
  (let* ((mc (make-instance 'mesh-constructor))
	 (ivquantity 8)
	 (itquantity 12))
    (with-slots ((m_akvertex vertices) (m_aknormals normals)
		 (m_aiindex indices) (m_akuv uvs)) mc
      (create-data mc ivquantity itquantity color)
      (%set-vertex m_akvertex 0 (vector (- fxextent) (- fyextent) (- fzextent)))
      (%set-vertex m_akvertex 1 (vector fxextent (- fyextent) (- fzextent)))
      (%set-vertex m_akvertex 2 (vector fxextent fyextent (- fzextent)))
      (%set-vertex m_akvertex 3 (vector (- fxextent) fyextent (- fzextent)))
      (%set-vertex m_akvertex 4 (vector (- fxextent) (- fyextent) fzextent))
      (%set-vertex m_akvertex 5 (vector fxextent (- fyextent) fzextent))
      (%set-vertex m_akvertex 6 (vector fxextent fyextent fzextent))
      (%set-vertex m_akvertex 7 (vector (- fxextent) fyextent fzextent))
      (when uvs-p
	(set-uv m_akuv 0 (vector 0.25 0.75))
	(set-uv m_akuv 1 (vector 0.75 0.75))
	(set-uv m_akuv 2 (vector 0.75 0.25))
	(set-uv m_akuv 3 (vector 0.25 0.25))
	(set-uv m_akuv 4 (vector 0.0 1.0))
	(set-uv m_akuv 5 (vector 1.0 1.0))
	(set-uv m_akuv 6 (vector 1.0 0.0))
	(set-uv m_akuv 7 (vector 0.0 0.0)))
      (setf (svref m_aiindex 0) 0)
      (setf (svref m_aiindex 1) 2)
      (setf (svref m_aiindex 2) 1)
      (setf (svref m_aiindex 3) 0)
      (setf (svref m_aiindex 4) 3)
      (setf (svref m_aiindex 5) 2)
      (setf (svref m_aiindex 6) 0)
      (setf (svref m_aiindex 7) 1)
      (setf (svref m_aiindex 8) 5)
      (setf (svref m_aiindex 9) 0)
      (setf (svref m_aiindex 10) 5)
      (setf (svref m_aiindex 11) 4)
      (setf (svref m_aiindex 12) 0)
      (setf (svref m_aiindex 13) 4)
      (setf (svref m_aiindex 14) 7)
      (setf (svref m_aiindex 15) 0)
      (setf (svref m_aiindex 16) 7)
      (setf (svref m_aiindex 17) 3)
      (setf (svref m_aiindex 18) 6)
      (setf (svref m_aiindex 19) 4)
      (setf (svref m_aiindex 20) 5)
      (setf (svref m_aiindex 21) 6)
      (setf (svref m_aiindex 22) 7)
      (setf (svref m_aiindex 23) 4)
      (setf (svref m_aiindex 24) 6)
      (setf (svref m_aiindex 25) 5)
      (setf (svref m_aiindex 26) 1)
      (setf (svref m_aiindex 27) 6)
      (setf (svref m_aiindex 28) 1)
      (setf (svref m_aiindex 29) 2)
      (setf (svref m_aiindex 30) 6)
      (setf (svref m_aiindex 31) 2)
      (setf (svref m_aiindex 32) 3)
      (setf (svref m_aiindex 33) 6)
      (setf (svref m_aiindex 34) 3)
      (setf (svref m_aiindex 35) 7)
      (when inside-p
	(reverse-triangle-order mc itquantity))
      (when normals-p
	(setf m_aknormals (compute-model-normals m_akvertex m_aiindex)))
      mc)))

(defun standard-sphere-mesh (izsamples iradialsamples fradius &key (uvs-p nil)
								(normals-p nil) (inside-p nil))
  (let* ((mc (make-instance 'mesh-constructor))
	 (izsm1 (- izsamples 1))
	 (izsm2 (- izsamples 2))
	 (izsm3 (- izsamples 3))
	 (irsp1 (+ iradialsamples 1))
	 (ivquantity (+ (* izsm2 irsp1) 2))
	 (itquantity (* (* 2 izsm2) iradialsamples))
	 (finvrs (/ 1.0 iradialsamples))
	 (fzfactor (/ 2.0 izsm1))
	 (afcos (make-array irsp1))
	 (afsin (make-array irsp1))
	 (i 0)
	 (izstart 0)
	 (ailocalindex 0)
	 ivqm1 ivqm2 ioffset 
	 i0 i1 i2 i3)
    (with-slots ((m_akvertex vertices) (m_aknormal normals)
		 (m_aiindex indices) (m_akuv uvs)
		 (m_binside inside-p)) mc  
      (let* (mc)
	(dotimes (ir iradialsamples)
	  (let ((fangle (coerce (* (* 2 pi finvrs) ir) 'single-float)))
	    (setf (svref afcos ir) (cos fangle))
	    (setf (svref afsin ir) (sin fangle))))
	(setf (svref afsin iradialsamples) (svref afsin 0))
	(setf (svref afcos iradialsamples) (svref afcos 0))
	(loop for iz from 1 below izsm1
	   doing
	   (let* ((fzfraction (+ -1.0 (* fzfactor iz)))
		  (fz (* fradius fzfraction))
		  (kslicecenter (vector 0.0 0.0 fz))
		  (fsliceradius (sqrt (abs (- (* fradius fradius) (* fz fz)))))
		  (isave i))
	     (dotimes (ir iradialsamples)
	       (let* ((fradialfraction (* ir finvrs))
		      (kradial (vector (svref afcos ir) (svref afsin ir) 0.0)))
		 (%set-vertex m_akvertex i (m+ kslicecenter (m* fsliceradius kradial)))
		 (when normals-p
		   (let ((knormal (copy-seq (%get-vertex m_akvertex i))))
		     (normalize knormal)
		     (if inside-p
			 (setf (svref m_aknormal i) (mneg knormal))
			 (setf (svref m_aknormal i) knormal))))
		 (when uvs-p
		   (set-uv m_akuv i fradialfraction)
		   (set-uv m_akuv i (* 0.5 (+ fzfraction 1.0))))
		 (incf i)))
	     (%set-vertex m_akvertex i (%get-vertex m_akvertex isave))
	     (when normals-p
	       (setf (svref m_aknormal i) (svref m_aknormal isave)))
	     (when uvs-p
	       (set-uv m_akuv i 1.0)
	       (set-uv m_akuv i (* 0.5 (+ fzfraction 1.0))))
	     (incf i)))
	(%set-vertex m_akvertex i (m* (- fradius) (unit-z-vector 3)))
	(when normals-p
	  (if inside-p
	      (setf (svref m_aknormal i) (unit-z-vector))
	      (setf (svref m_aknormal i) (mneg (unit-z-vector 3)))))
	(when uvs-p
	  (set-uv m_akuv i 0.5)
	  (set-uv m_akuv i 0.0))
	(incf i)
	(%set-vertex m_akvertex i (m* fradius (unit-z-vector 3)))
	(when normals-p
	  (if m_binside 
	      (setf (svref m_aknormal i) (mneg (unit-z-vector 3)))
	      (setf (svref m_aknormal i) (unit-z-vector 3))))
	(when uvs-p
	  (set-uv m_akuv i 0.5)
	  (set-uv m_akuv i 1.0))
	(incf i)
	(assert (= i ivquantity))
	(dotimes (iz izsm3)
	  (setf i0 izstart)
	  (setf i1 (+ i0 1))
	  (incf izstart irsp1)
	  (setf i2 izstart)
	  (setf i3 (+ i2 1))
	  (dotimes (i iradialsamples)
	    (if inside-p
                (progn
                  (setf (svref m_aiindex (+ ailocalindex 0)) (post-incf i0))
                  (setf (svref m_aiindex (+ ailocalindex 1)) i2)
                  (setf (svref m_aiindex (+ ailocalindex 2)) i1)
                  (setf (svref m_aiindex (+ ailocalindex 3)) (post-incf i1))
                  (setf (svref m_aiindex (+ ailocalindex 4)) (post-incf i2))
                  (setf (svref m_aiindex (+ ailocalindex 5)) (post-incf i3)))
		(progn
		  (setf (svref m_aiindex (+ ailocalindex 0)) (post-incf i0))
		  (setf (svref m_aiindex (+ ailocalindex 1)) i1)
		  (setf (svref m_aiindex (+ ailocalindex 2)) i2)
		  (setf (svref m_aiindex (+ ailocalindex 3)) (post-incf i1))
		  (setf (svref m_aiindex (+ ailocalindex 4)) (post-incf i3))
		  (setf (svref m_aiindex (+ ailocalindex 5)) (post-incf i2))))
	    (incf ailocalindex 6)))
	(setf ivqm2 (- ivquantity 2))
	(dotimes (i iradialsamples)
	  (if inside-p
	      (progn 
		(setf (svref m_aiindex (+ ailocalindex 0)) i)
		(setf (svref m_aiindex (+ ailocalindex 1)) (+ i 1))
		(setf (svref m_aiindex (+ ailocalindex 2)) ivqm2))
	      (progn 
		(setf (svref m_aiindex (+ ailocalindex 0)) i)
		(setf (svref m_aiindex (+ ailocalindex 1)) ivqm2)
		(setf (svref m_aiindex (+ ailocalindex 2)) (+ i 1))))
	  (incf ailocalindex 3))
	(setf ivqm1 (- ivquantity 1))
	(setf ioffset (* izsm3 irsp1))
	(dotimes (i iradialsamples)
	  (if inside-p
	      (progn 
		(setf (svref m_aiindex (+ ailocalindex 0)) (+ i ioffset))
		(setf (svref m_aiindex (+ ailocalindex 1)) ivqm1)
		(setf (svref m_aiindex (+ ailocalindex 2)) (+ i 1 ioffset)))
	      (progn 
		(setf (svref m_aiindex (+ ailocalindex 0)) (+ i ioffset))
		(setf (svref m_aiindex (+ ailocalindex 1)) (+ i 1 ioffset))
		(setf (svref m_aiindex (+ ailocalindex 2)) ivqm1)))
	  (incf ailocalindex 3))
					;(assert (= ailocalindex (+ m_aiindex (* 3 itquantity))))
	mc))))


;;; Making the user use Mesh Constructors to make trimesh
;;; objects is cumbersome.  The below is an attempt to make that
;;; slightly less so.


(defun make-rectangle (pos width height &key (xsamples 2) (ysamples 2) (color #(1.0 1.0 1.0))
					  name)
  (let* ((mesh (rectangle xsamples ysamples width height :color color :normals-p t :uvs-p t))
	 (geom (make-instance 'trimesh
			      :vertices (vertices mesh)
			      :indices (indices mesh)
			      :colors (colors mesh)
			      :normals (normals mesh)
			      :texcoords (uvs mesh)
			      :name (or name (gensym "RECTANGLE"))
			      :vao-format '(:|v3f| :|c3f| :|t2f| :|n3f|))))
	   
    (set-position geom pos)
    (initialize-data geom nil)
    geom))

(defun make-disk (pos radius &key (resolution 20) (color #(1.0 1.0 1.0)))
  (let* ((mesh (disk resolution resolution radius :color color :normals-p t :uvs-p t))
	 (geom (make-instance 'trimesh
			      :vertices (vertices mesh)
			      :indices (indices mesh)
			      :colors (colors mesh)
			      :normals (normals mesh)
			      :texcoords (uvs mesh))))
    (set-position geom pos)
    geom))


(defun make-box (pos &key (scale-x 1.0) (scale-y 1.0) (scale-z 1.0) (color #(1.0 1.0 1.0)))
  (let* ((mesh (standard-box-mesh scale-x scale-y scale-z :color color :normals-p t :uvs-p t))
	 (geom (make-instance 'trimesh
			      :vertices (vertices mesh)
			      :indices (indices mesh)
			      :colors (colors mesh)
			      :normals (normals mesh)
			      :texcoords (uvs mesh)
			      :vao-format '(:|v3f| :|c3f| :|t2f| :|n3f|))))
    (set-position geom pos)
    (initialize-data geom nil)
    geom))

(defclass rectangle (trimesh)
  ((width  :accessor get-width  :initarg :width :initform 1.0)
   (height :accessor get-height :initarg :height :initform 1.0))
  (:default-initargs
   :name (gensym "RECTANGLE-")
    :colors #(1.0 1.0 1.0)))

(defmethod initialize-instance :after ((r rectangle) &rest initargs)
  (declare (ignore initargs))
  (with-slots (v c n i tc width height vao-format) r
    (let ((mesh (rectangle 2 2 width height :color c :normals-p t :uvs-p t)))
      (setf v (vertices mesh)
	    i (indices mesh)
	    c (colors mesh)
	    n (normals mesh)
	    tc (uvs mesh)
	    vao-format '(:|v3f| :|c3f| :|t2f| :|n3f|))
      (initialize-data r nil))))

